package com.imooc.sell.service.impl;

import com.imooc.sell.dao.OrderDetailDao;
import com.imooc.sell.dao.OrderMasterDao;
import com.imooc.sell.dao.ProductInfoDao;
import com.imooc.sell.dao.UserDao;
import com.imooc.sell.dataobject.OrderDetail;
import com.imooc.sell.dataobject.OrderMaster;
import com.imooc.sell.dataobject.ProductInfo;
import com.imooc.sell.dataobject.User;
import com.imooc.sell.dto.CartDTO;
import com.imooc.sell.dto.OrderDTO;
import com.imooc.sell.enums.OrderStatusEnum;
import com.imooc.sell.enums.PayStatusEnum;
import com.imooc.sell.expection.SellExpection;
import com.imooc.sell.service.OrderService;
import com.imooc.sell.enums.ErrorEnum;
import com.imooc.sell.utils.wang.JudgeUtils;
import com.imooc.sell.utils.wang.OrderConvertUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.OrderUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 订单业务实现类
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    public OrderServiceImpl() {
    }

    /**
     * 操作用户表的dao
     */
    @Autowired
    private UserDao userDao;

    /**
     * 操作订单详情的dao
     */
    @Autowired
    private OrderDetailDao detailDao;

    /**
     * 操作主订单表的dao
     */
    @Autowired
    private OrderMasterDao masterDao;

    /**
     * 产品相关的dao
     */
    @Autowired
    private ProductInfoDao productInfoDao;

    @Override
    public User getUserBaseInfo(String openid) throws SellExpection {
        User user;
        try {
            user = userDao.getOne(openid);
        } catch (Exception e) {
            log.error("{}[查询用户基本信息]：未查找到指定openid的用户", getClass());
            throw new SellExpection(ErrorEnum.USER_NOT_FOUND);
        }
        return user;
    }

    @Transactional
    @Override
    public OrderDTO orderSave(OrderDTO orderDTO) throws SellExpection {
        //1.订单主表入库
        OrderMaster orderMaster = new OrderMaster();
        BeanUtils.copyProperties(orderDTO, orderMaster);
        //设置订单状态
        orderMaster.setOrderStatus(OrderStatusEnum.ORDER_STATUS_NEW.getCode());
        orderMaster.setPayStatus(PayStatusEnum.PAY_STATUS_WAIT.getCode());

        //记录订单id
        String orderId = masterDao.save(orderMaster).getOrderId();

        List<OrderDetail> detailList = orderDTO.getOrderDetailList();
        List<String> proIdList = new ArrayList<>();

        //2.订单详情入库并扣除库存
        //判断详情列表是否为null
        if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())) {
            log.error("{}[提交订单]，订单详情列表为空", getClass());
            throw new SellExpection(ErrorEnum.ORDER_DETAIL_NULL);
        }

        //获取产品id列表
        for (OrderDetail orderDetail : detailList) {
            if (orderDetail.getProductId() == null) {
                log.error("{}[创建订单]，订单详情中存在空productId", getClass());
                throw new SellExpection(ErrorEnum.PRODUCT_ID_IS_NULL);
            }
            proIdList.add(orderDetail.getProductId());
        }

        //获取所有orderId存在于proIdList中的对象,用户判断是否存在数据库中没有的商品
        //jpa中find若没有查到值，不会返回null对象，相当于不存在，所以此处可用长度判断
        //是否有不存在的productId
        if (productInfoDao.findAllById(proIdList).size() != proIdList.size()) {
            log.error("{}[提交订单]，订单中的某些商品不存在", getClass());
            throw new SellExpection(ErrorEnum.PRODUCT_NOT_FOUND);
        }

        //为详情设置orderId
        for (OrderDetail orderDetail : detailList) {
            //设置detail的OrderId
            orderDetail.setOrderId(orderId);
        }
        /*判断是否已经预下单 */
        if (!checkOrderDetail(orderId)) {
            detailDao.saveAll(detailList);
        }


        //3.修改库存
        //获取购物车列表(商品id，商品数量列表),使用拉姆达表达式列表赋值
        List<CartDTO> cartDTOList = orderDTO.getOrderDetailList().stream()
                .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
                .collect(Collectors.toList());
        reduceStock(cartDTOList);

        return OrderConvertUtils.convert(masterDao.getOne(orderId));
    }

    /**
     * 判断是否预下单
     *
     * @param orderId 订单号
     * @return 是:true 否:false
     */
    private boolean checkOrderDetail(String orderId) {
        return detailDao.findAllByOrderId(orderId).size() != 0;
    }

    @Transactional
    @Override
    public OrderDTO cancel(OrderDTO orderDTO) throws SellExpection {
        //判断订单是否存在
        OrderMaster master = JudgeUtils.OrderIsExist(orderDTO.getOrderId(), masterDao);

        //判断订单状态
        JudgeUtils.judgeOrderStatus("[取消订单]", master.getOrderStatus(), OrderStatusEnum.ORDER_STATUS_NEW.getCode());


        //修改订单状态
        master.setOrderStatus(OrderStatusEnum.ORDER_STATUS_CANCLE.getCode());
        masterDao.save(master);

        //库存回滚
        List<OrderDetail> detailList = detailDao.findAllByOrderId(orderDTO.getOrderId());
        if (CollectionUtils.isEmpty(detailList)) {
            log.error("{}[取消订单]，订单详情为空，orderId={}", getClass(), orderDTO.getOrderId());
            throw new SellExpection(ErrorEnum.ORDER_DETAIL_NULL);
        }

        //利用拉姆达表达式对列表进行属性赋值
        List<CartDTO> cartDTOList = detailList.stream()
                .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
                .collect(Collectors.toList());
        increaseStock(cartDTOList);

        return orderDTO;
    }

    @Transactional
    @Override
    public OrderDTO payBack(String orderId) throws SellExpection {
        //判断订单是否存在
        OrderMaster orderMaster = JudgeUtils.OrderIsExist(orderId, masterDao);

        //判断订单状态
        JudgeUtils.judgeOrderStatus("[退款]", orderMaster.getOrderStatus(), OrderStatusEnum.ORDER_STATUS_COMMENT.getCode());

        //查询支付状态
        JudgeUtils.judgePayStatus("[退款]", orderMaster.getPayStatus(), PayStatusEnum.PAY_STATUS_FINISH.getCode());

        //修改支付状态为退款中,在卖家端同意退款之后修改为退款成功状态，卖家不同意则修改回支付完成状态
        //订单状态在退款成功后修改为已完成，退款失败不变
        orderMaster.setPayStatus(PayStatusEnum.PAY_STATUS_BACKING.getCode());
        masterDao.save(orderMaster);

        OrderDTO orderDTO = new OrderDTO();
        BeanUtils.copyProperties(orderMaster, orderDTO);
        return orderDTO;
    }

    @Transactional
    @Override
    public OrderDTO paid(String orderId) throws SellExpection {
        //判断订单是否存在
        OrderMaster master = JudgeUtils.OrderIsExist(orderId, masterDao);

        //判断订单状态
        JudgeUtils.judgeOrderStatus("[订单支付]", master.getOrderStatus(), OrderStatusEnum.ORDER_STATUS_NEW.getCode());

        //查询支付状态
        JudgeUtils.judgePayStatus("[订单支付]", master.getPayStatus(), PayStatusEnum.PAY_STATUS_WAIT.getCode());

        //修改支付状态
        master.setPayStatus(PayStatusEnum.PAY_STATUS_FINISH.getCode());
        //支付完成之后应该将订单状态改为待评价
        master.setOrderStatus(OrderStatusEnum.ORDER_STATUS_COMMENT.getCode());
        OrderMaster updateMaster = masterDao.save(master);

        OrderDTO orderDTO = new OrderDTO();
        BeanUtils.copyProperties(updateMaster, orderDTO);
        return orderDTO;
    }

    @Override
    public OrderDTO findOneOrderMaster(String orderId) {
        OrderDTO orderDTO;
        //判断订单是否存在
        OrderMaster master = JudgeUtils.OrderIsExist(orderId, masterDao);
        orderDTO = OrderConvertUtils.convert(master);
        return orderDTO;
    }

    @Override
    public OrderDTO findOneOrder(String orderId) throws SellExpection {
        //查询订单主表
        OrderMaster master = JudgeUtils.OrderIsExist(orderId, masterDao);
        OrderDTO orderDTO = OrderConvertUtils.convert(master);

        //查询订单详情
        List<OrderDetail> detailList = detailDao.findAllByOrderId(orderId);
        if (CollectionUtils.isEmpty(detailList)) {
            log.error("{}[查询单个订单]，该订单订单详情为空，订单号:{}", getClass(), orderId);
            throw new SellExpection(ErrorEnum.ORDER_DETAIL_NULL);
        }
        orderDTO.setOrderDetailList(detailList);

        return orderDTO;
    }

    @Override
    public Page<OrderDTO> findOrderList(String openid, Pageable pageable) {
        Page<OrderMaster> pageMaster = masterDao.findAllByBuyerOpenid(openid, pageable);
        List<OrderDTO> orderDTOList = OrderConvertUtils.convert(pageMaster.getContent());
        return new PageImpl<>(orderDTOList);
    }

    @Override
    public List<OrderDetail> findDetailList(String orderId) {
        return detailDao.findAllByOrderId(orderId);
    }

    @Override
    public List<OrderDTO> findAllOrderListByOpenid(String openid) {
        return OrderConvertUtils.convert(masterDao.findAllByBuyerOpenidAndBuyerPhoneIsNotNullOrderByCreateTimeDesc(openid));
    }

    @Transactional
    @Override
    public void reduceStock(List<CartDTO> cartDTOList) throws SellExpection {
        List<String> proIdList = new ArrayList<>();
        //获取产品id列表
        for (CartDTO cartDTO : cartDTOList) {
            proIdList.add(cartDTO.getProductId());
        }

        //判断是有不存在的product_id
        List<ProductInfo> productInfoList = productInfoDao.findAllById(proIdList);
        if (productInfoList.size() != proIdList.size()) {
            log.error("{}[提交订单]，订单中的某些商品不存在", getClass());
            throw new SellExpection(ErrorEnum.PRODUCT_NOT_FOUND);
        }

        for (ProductInfo productInfo : productInfoList) {
            for (CartDTO cartDTO : cartDTOList) {
                if (productInfo.getId().equals(cartDTO.getProductId())) {
                    int resultAmount = productInfo.getProductStock() - cartDTO.getQuantity();
                    if (resultAmount < 0) {
                        log.error("{}[提交订单],库存不够 productId={}", getClass(), productInfo.getId());
                        throw new SellExpection(ErrorEnum.PRODUCT_STOCK_NOT_ENOUGH);
                    }

                    productInfo.setProductStock(resultAmount);
                    //比较之后删除,以减少内层循环次数
                    cartDTOList.remove(cartDTO);
                    break;
                }
            }
        }
        productInfoDao.saveAll(productInfoList);
    }

    @Transactional
    @Override
    public void increaseStock(List<CartDTO> cartDTOList) {
        List<String> proIdList = new ArrayList<>();
        //获取产品id列表
        for (CartDTO cartDTO : cartDTOList) {
            proIdList.add(cartDTO.getProductId());
        }

        //判断是有不存在的product_id
        List<ProductInfo> productInfoList = productInfoDao.findAllById(proIdList);
        if (productInfoList.size() != proIdList.size()) {
            log.error("{}[提交订单]，订单中的某些商品不存在", getClass());
            throw new SellExpection(ErrorEnum.PRODUCT_NOT_FOUND);
        }

        for (ProductInfo productInfo : productInfoList) {
            for (CartDTO cartDTO : cartDTOList) {
                if (productInfo.getId().equals(cartDTO.getProductId())) {
                    int resultAmount = productInfo.getProductStock() + cartDTO.getQuantity();
                    productInfo.setProductStock(resultAmount);
                    //比较之后删除,以减少内层循环次数
                    cartDTOList.remove(cartDTO);
                    break;
                }
            }
        }
        productInfoDao.saveAll(productInfoList);
    }

    @Transactional
    @Override
    public OrderDTO sellerCancel(String orderId) {

        OrderMaster master;
        //判断订单状态，必须要是待评价状态才能取消
        master = JudgeUtils.OrderIsExist(orderId, masterDao);
        JudgeUtils.judgeOrderStatus("[卖家取消订单]", master.getOrderStatus(), OrderStatusEnum.ORDER_STATUS_COMMENT.getCode());

        //判断支付状态是否为已支付
        JudgeUtils.judgePayStatus("[卖家取消订单]", master.getPayStatus(), PayStatusEnum.PAY_STATUS_FINISH.getCode());

        //修改订单状态为已取消
        master.setOrderStatus(OrderStatusEnum.ORDER_STATUS_CANCLE.getCode());
        //修改支付状态为退款成功
        master.setPayStatus(PayStatusEnum.PAY_STATUS_BACK.getCode());
        OrderMaster resultMaster = masterDao.save(master);

        //库存回滚
        List<OrderDetail> detailList = detailDao.findAllByOrderId(orderId);
        if (CollectionUtils.isEmpty(detailList)) {
            log.error("{}[取消订单]，订单详情为空，orderId={}", getClass(), orderId);
            throw new SellExpection(ErrorEnum.ORDER_DETAIL_NULL);
        }

        //利用拉姆达表达式对列表进行属性赋值
        List<CartDTO> cartDTOList = detailList.stream()
                .map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()))
                .collect(Collectors.toList());
        increaseStock(cartDTOList);

        //调用支付宝退款接口
        //TODO

        return OrderConvertUtils.convert(resultMaster);
    }

    @Transactional
    @Override
    public OrderDTO agreePayBack(String orderId, boolean isAgree) {
        //判断订单是否存在
        OrderMaster master = JudgeUtils.OrderIsExist(orderId, masterDao);
        //判断订单状态,待评价
        JudgeUtils.judgeOrderStatus("[商家退款判断]", master.getOrderStatus(), OrderStatusEnum.ORDER_STATUS_COMMENT.getCode());
        //判断支付状态,退款中
        JudgeUtils.judgePayStatus("[商家退款判断]", master.getPayStatus(), PayStatusEnum.PAY_STATUS_BACKING.getCode());

        //通过isAgree判断商家是否同意退款
        //同意则修改支付状态为退款成功，订单状态为已完成
        //否则支付状态从退款中修改为已完成，订单状态不变
        if (isAgree) {
            master.setOrderStatus(OrderStatusEnum.ORDER_STATUS_FINISH.getCode());
            master.setPayStatus(PayStatusEnum.PAY_STATUS_BACK.getCode());

            //调用支付宝退款接口退款
            //TODO
        } else {
            master.setPayStatus(PayStatusEnum.PAY_STATUS_FINISH.getCode());
        }
        //存储
        OrderMaster resultMaster = masterDao.save(master);

        return OrderConvertUtils.convert(resultMaster);
    }

    @Transactional
    @Override
    public OrderDTO agreePayBack2(String orderId, boolean isAgree) {
        //判断订单是否存在
        OrderMaster master = JudgeUtils.OrderIsExist(orderId, masterDao);
        //判断订单状态,待评价
        JudgeUtils.judgeOrderStatus("[商家退款判断]", master.getOrderStatus(), OrderStatusEnum.ORDER_STATUS_COMMENT.getCode());
        try {
            //判断支付状态,退款中
            JudgeUtils.judgePayStatus("[商家退款判断]", master.getPayStatus(), PayStatusEnum.PAY_STATUS_BACKING.getCode());
        } catch (Exception e) {
            JudgeUtils.judgePayStatus("[商家退款判断]", master.getPayStatus(), PayStatusEnum.PAY_STATUS_FINISH.getCode());
        }
        //通过isAgree判断商家是否同意退款
        //同意则修改支付状态为退款成功，订单状态为已完成
        //否则支付状态从退款中修改为已完成，订单状态不变
        if (isAgree) {
            master.setOrderStatus(OrderStatusEnum.ORDER_STATUS_FINISH.getCode());
            master.setPayStatus(PayStatusEnum.PAY_STATUS_BACK.getCode());

            //调用支付宝退款接口退款
            //TODO
        } else {
            master.setPayStatus(PayStatusEnum.PAY_STATUS_FINISH.getCode());
        }
        //存储
        OrderMaster resultMaster = masterDao.save(master);

        return OrderConvertUtils.convert(resultMaster);
    }

    @Override
    public Page<OrderDTO> findPayingBackOrderList(Pageable pageable) {
        //退款中的状态
        final short payStatus = 3;
        //分页查询
        Page<OrderMaster> page = masterDao.findAllByPayStatusOrderByCreateTimeDesc(payStatus, pageable);
        //转换为数据传输对象
        List<OrderDTO> orderDTOList = OrderConvertUtils.convert(page.getContent());
        //利用list和page构建pageImpl对象
        return new PageImpl<>(orderDTOList, pageable, page.getTotalElements());
    }

    public Page<OrderDTO> findAllByOrderStatusAndCreateTimeBetweenOrderByCreateTime(
            Short orderStatus, Date startDate, Date endDate, Pageable pageable) {
        //分页查询
        Page<OrderMaster> page =
                masterDao.findAllByOrderStatusAndCreateTimeBetweenOrderByCreateTimeDesc(orderStatus, startDate, endDate, pageable);
        //转换为数据传输对象
        List<OrderDTO> orderDTOList = OrderConvertUtils.convert(page.getContent());
        //利用list和page构建pageImpl对象
        return new PageImpl<>(orderDTOList, pageable, page.getTotalElements());
    }
}
